#!/usr/bin/python2

### gdrive_backup
# homepage: http://code.google.com/p/gdrive-backup
# written by shaun martin (shaun@samsite.ca)
# v0.8: jan 10 2013

### TODO
# - Add folder support
# - Add graceful handling of httplib2 failures.

### Google API Client Information
# You'll need to enable the Google Drive API and sign up
# See: https://developers.google.com/drive/quickstart-python
CLIENT_ID = ''
CLIENT_SECRET = ''

### Trashed Files
# Back em up? Set to true
TRASHED = "false"

### Backup Folder
# This is where all your files will be downloaded to. Trailing slash req'd.
# gdrive_backup will check files in this folder to see if they're the same age or
# newer than the files on Google Drive and skip them if so. However, if you have files in
# this directory already then you risk having them overwritten without warning!
DESTINATION = "/mnt/backup/gdrive/"

### Format Conversions
# Google helpfully provides a mechanism to convert Google Drive files into
# formats that can be read by other applications. Uncomment any line to download
# your file(s) in that format.
# NOTE: Forms can't be converted and thus, aren't supported for download yet.
# WARNING: Downloading lots of files in more than 1 format is going to take a long
#	   damn time. Best to just pick one.

CONVERT_DOCUMENT = {
#	'html': 'text/html',
#	'txt': 'text/'plain',
#	'rtf': 'application/rtf',
#	'pdf': 'application/pdf',
#	'odt': 'application/vnd.oasis.opendocument.text',
	'docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
}

CONVERT_SPREADSHEET = {
#	'pdf': 'application/pdf',
#	'ods': 'application/vnd.oasis.opendocument.spreadsheet',
	'xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
}

CONVERT_DRAWING = {
#	'jpeg': 'image/jpeg',
#	'png': 'image/png',
	'svg': 'image/svg+xml',
#	'pdf': 'application/pdf',
}

CONVERT_PRESENTATION = {
#	'pdf': 'application/pdf',
	'pptx': 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
}


# Ignored mimes
# Folders and Forms aren't supported yet.
IGNORED_MIMES = {
	'application/vnd.google-apps.folder',
	'application/vnd.google-apps.form'
}

#################################################################
#### You probably don't want to dick with stuff past here... ####
#################################################################

import httplib2
import pprint
import os
import time

from datetime import datetime
from apiclient import errors
from apiclient.discovery import build
from apiclient.http import MediaFileUpload
from oauth2client.client import OAuth2WebServerFlow
from oauth2client.file import Storage

### Functions
def get_file_list(service, trashed):
	"""Retrieve a list of File resources.
		cribbed directly from the google tutorial

	Args:
		service: Drive API service instance.
	Returns:
		List of File resources.
	"""
	result = []
	page_token = None
	while True:
		try:
			param = {}
			param['q'] = 'trashed = %s' % trashed
			if page_token:
				param['pageToken'] = page_token
			files = service.files().list(**param).execute()

			result.extend(files['items'])
			page_token = files.get('nextPageToken')
			if not page_token:
				break
		except errors.HttpError, error:
			print 'An error occurred: %s' % error
			break
	return result

def download(filename,gmtime,url,service):
	"""Download a file
		most of this function was cribbed from the google tutorial

	Args:
		filename: full path to destination file incl name
		mtime: Google's listed modified date
		url
		service: google drive api service instance
	Return:
		destination filename on success, None on failure
	"""
	# convert google's mod time string to something useful
	# google's dt format as of Jan 10 2013: 2013-01-10T03:56:20.559Z
	mtime = time.strptime(gmtime,"%Y-%m-%dT%H:%M:%S.%fZ")

	# check to see if local file is newer
	if os.path.exists(filename):
		finfo = os.stat(filename)
		if time.mktime(mtime) <= finfo.st_mtime:
			print "WARN: Local version of %s appears to be the same age or newer than the Google Drive version. Skipping." % filename
			return None 
	
	if url:
		resp, content = service._http.request(url)
		if resp.status == 200:
			try:
				f = open(filename,'w')
				f.write(content)
				f.close()
				
				# update modified time to match google's
				os.utime(filename,(time.mktime(datetime.now().timetuple()),time.mktime(mtime)))
			except IOError:
				print "ERROR: Unable to write to file %s" % filename
			else:
				return filename
		else:
			print 'ERROR: Unable to download file. HTTP Response: %s' % resp
			return None
	else:
		# The file doesn't have any content stored on Drive.
		return None


# Google Drive file types
gdrive_mimes = {
	'application/vnd.google-apps.document': { 'name': 'Document', 'convert_to': CONVERT_DOCUMENT },
	'application/vnd.google-apps.spreadsheet': { 'name': 'Spreadsheet', 'convert_to': CONVERT_SPREADSHEET },
	'application/vnd.google-apps.drawing': { 'name': 'Drawing', 'convert_to': CONVERT_DRAWING },
	'application/vnd.google-apps.presentation': { 'name': 'Presentation', 'convert_to': CONVERT_PRESENTATION },
}

# Auth consts
OAUTH_SCOPE = 'https://www.googleapis.com/auth/drive'
REDIRECT_URI = 'urn:ietf:wg:oauth:2.0:oob'

# Run through OAuth flow to get creds...
storage = Storage('%s.creds' % DESTINATION)
credentials = storage.get()

if credentials is None:
	flow = OAuth2WebServerFlow(CLIENT_ID, CLIENT_SECRET, OAUTH_SCOPE, REDIRECT_URI)
	authorize_url = flow.step1_get_authorize_url()
	print 'Go to the following link in your browser: ' + authorize_url
	code = raw_input('Enter verification code: ').strip()
	credentials = flow.step2_exchange(code)
	storage.put(credentials)

# Create HTTP obj, auth it and set up the gdrive service
http = httplib2.Http()
http = credentials.authorize(http)

drive_service = build('drive', 'v2', http=http)

filelist = get_file_list(drive_service,TRASHED)

for file in filelist:
	# is it ignored?
	if file['mimeType'] in IGNORED_MIMES:
		print "Ignoring %s. Reason: %s in ignore list" % (file['title'], file['mimeType'])
		continue
	
	# is it a google drive file format?
	if file['mimeType'] in gdrive_mimes.keys():
		print "Found Google Drive %s %s..." % (gdrive_mimes[file['mimeType']]['name'], file['title'])
		for ext, mime in gdrive_mimes[file['mimeType']]['convert_to'].iteritems():
			result = download("%s%s.%s" % (DESTINATION,file['title'],ext), file['modifiedDate'], file['exportLinks'][mime], drive_service)
			if result is not None:
				print "... Successfully converted and downloaded to %s.%s" % (file['title'],ext)
		continue

	# it must be some normal file type. let's download it.
	result = download("%s%s" % (DESTINATION,file['title']), file['modifiedDate'], file['downloadUrl'], drive_service)
	if result is not None:
		print "Successfully downloaded %s" % file['title']

		
